package threadpoolnio.server;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * @author ：xx
 * @date ：Created in 2020/3/17 20:20
 * @description：
 * @modified By：
 */
public class ReaderThread implements Runnable {
    SelectionKey key = null;
    Map<SelectionKey, FileChannel> fileMap = null;
    Map<SelectionKey, Long> timeMap = null;

    public ReaderThread(SelectionKey key, Map<SelectionKey, FileChannel> fileMap, Map<SelectionKey, Long> timeMap) {
        this.key = key;
        this.fileMap = fileMap;
        this.timeMap = timeMap;
    }

    @Override
    public void run() {
        readHelper();
    }

    public void readHelper() {
        //拿到Selector 中channel
        SocketChannel sc = (SocketChannel) key.channel();
        ByteBuffer buf = (ByteBuffer) key.attachment();
        FileChannel fileChannel = fileMap.get(key);
        try {
            int bytesRead = -1;
            boolean isFile = false;
            while ((bytesRead = sc.read(buf)) > 0) {
                buf.flip();
                int type = buf.getInt();
                if (type == 0 && fileChannel == null) {
                    isFile = false;
                    System.out.println("===========" + sc.getRemoteAddress() + "文本消息=================");
                }
                if (type == 1 || type == 2 || fileChannel != null) {
                    isFile = true;
                }
                if (type == 1 && fileChannel == null) {
                    System.out.println("=============" + sc.getRemoteAddress() + "文件数据=============");
                    String filename = null;
                    int fileNameLength = buf.getInt();
                    long fileSize = buf.getLong();
                    byte[] nameBytes = new byte[fileNameLength];
                    buf.get(nameBytes);
                    filename = new String(nameBytes, 0, fileNameLength, "utf-8");
                    System.out.println("文件名字：" + filename + ",长度：" + fileSize);
                    if (filename != null && filename.length() > 0) {
                        String currPath = System.getProperty("user.dir");
                        currPath = currPath + File.separator
                                + "upload" + File.separator + filename;
                        File file = new File(currPath);
                        if (!file.getParentFile().exists()) {
                            file.mkdirs();
                        }
                        fileChannel = new FileOutputStream(currPath).getChannel();
                        fileMap.put(key, fileChannel);
                        //存起来当前时间
                        timeMap.put(key, System.currentTimeMillis());
                    }
                }
                if (fileChannel != null)
                    isFile = true;
                if (!isFile) {
                    //为了处理中文做了特殊处理
                    byte[] bytes = new byte[1024];
                    int i = 0;
                    while (buf.hasRemaining()) {
                        bytes[i] = buf.get();
                        i++;
                    }
                    System.out.println(new String(bytes, "GBK"));
                } else {
                    //必须加循环判定，否则造成文件输出变大问题
                    while (buf.hasRemaining() && fileChannel != null) {
                        fileChannel.write(buf);
                    }
                }
                buf.clear();
            }

                //      key.cancel();
                if (fileChannel != null)
                    isFile = true;

                if (bytesRead == -1) {
                    if (isFile) {
//                    System.out.println("文件接收完成");
                        buf.clear();
                        Long startTime = timeMap.get(key);
                        long time = System.currentTimeMillis() - startTime;
                        String result = sc.getRemoteAddress() + "文件上传成功,耗时：" + time / 1000 + "s";
                        System.out.println(result);
                        buf.put(result.getBytes("GBK"));
                        buf.flip();
                        sc.write(buf);
                        sc.shutdownOutput();
                    }
                    if (fileChannel != null) {
                        fileChannel.close();
                        fileChannel = null;
                    }
                    buf.clear();
                    //            sc.close();
                    return;
                }
                // Channel的read方法可能返回0，返回0并不一定代表读取完了。
                // 工作线程结束对通道的读取，需要再次更新键的ready集合，将感兴趣的集合重新放在里面
                key.interestOps(key.interestOps() | SelectionKey.OP_READ);
                // 调用wakeup，使得选择器上的第一个还没有返回的选择操作立即返回即重新select
                key.selector().wakeup();
            } catch(IOException e){
                try {
                    System.out.println("==============" + sc.getRemoteAddress() + "已离线===========,原因：" + e.getMessage());
                    sc.close();
                    key.cancel();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }

    }
}